// vector, uses memmove
// $Id: fast_vector.h 518 2010-07-18 09:49:40Z Oleg.Bulychov $
#pragma once

#include "src/heo/include/mem_util.h"

template<class T, class AllocPolicy>
class fast_vector_impl
{
    DISALLOW_COPY_AND_ASSIGN(fast_vector_impl);
public:
    T* beg_;
    T* end_;
    T* eos_;
//.............................................................................
    typedef T value_type;
    typedef AllocPolicy TAllocPolicy;
//.............................................................................
    explicit fast_vector_impl() NO_THROW_(): beg_(), end_(), eos_()
    {}
//.............................................................................
    ~fast_vector_impl() NO_THROW_()
    {//:do not destruct ~T here
        AllocPolicy::Free(beg_);
    }
//.............................................................................
    void clear() NO_THROW_()
    {
        AllocPolicy::Free(beg_);
        beg_ = end_ = eos_ = NULL;
    }
//.............................................................................
    size_t size() const NO_THROW_()
    {
        return end_ - beg_;
    }
//.............................................................................
    size_t capacity() const NO_THROW_()
    {
        return eos_ - beg_;
    }
//.............................................................................
    bool is_Empty() const NO_THROW_()
    {
        return end_ == beg_;
    }
//.............................................................................
    bool empty() const NO_THROW_()//:this name is suxx
    {
        return is_Empty();
    }
//.............................................................................
    bool bad_Index(size_t index) const NO_THROW_()
    { 
        return index >= size();
    }
//.............................................................................
    T& operator[](size_t i) NO_THROW_()
    {
        ASSERT_(!bad_Index(i));
        return beg_[i];
    }
//.............................................................................
    T const& operator[](size_t i) const NO_THROW_()
    {
        ASSERT_(!bad_Index(i));
        return beg_[i];
    }
//.............................................................................
    T& get(size_t i) NO_THROW_()
    {
        ASSERT_(!bad_Index(i));
        return beg_[i];
    }
//.............................................................................
    T const& get(size_t i) const NO_THROW_()
    {
        ASSERT_(!bad_Index(i));
        return beg_[i];
    }
//.............................................................................
    T& front() NO_THROW_()
    {
        ASSERT_(!is_Empty());
        return *beg_;
    }
//.............................................................................
    T const& front() const NO_THROW_()
    {
        ASSERT_(!is_Empty());
        return *beg_;
    }
//.............................................................................
    T& back() NO_THROW_()
    {
        ASSERT_(!is_Empty());
        return *(end_ - 1);
    }
//.............................................................................
    T const& back() const NO_THROW_()
    {
        ASSERT_(!is_Empty());
        return *(end_ - 1);
    }
//.............................................................................
    T* begin() NO_THROW_()
    {
        return beg_;
    }
//.............................................................................
    T const* begin() const NO_THROW_()
    {
        return beg_;
    }
//.............................................................................
    T* end() NO_THROW_()
    {
        return end_;
    }
//.............................................................................
    T const* end() const NO_THROW_()
    {
        return end_;
    }
//.............................................................................
    T* get_Buffer() NO_THROW_() { return beg_; }
//.............................................................................
    void swap(fast_vector_impl<T, AllocPolicy>& right) NO_THROW_()
    {
        std::swap(beg_, right.beg_);
        std::swap(end_, right.end_);
        std::swap(eos_, right.eos_);
    }
//.............................................................................
    T& push_back()
    {
        if (eos_ == end_) 
            VERIFY_(reserve(AllocPolicy::New_Capacity(capacity() + 1)));
        new(end_) T;
        return *(end_++);
    }
//.............................................................................
    T* push_back(mem_util::no_check_null_t const&)
    {
        if (eos_ == end_) 
            if (!reserve(AllocPolicy::New_Capacity(capacity() + 1)))
                return NULL;
        new(end_) T;
        return end_++;
    }
//.............................................................................
    template<typename U>
    T* push_back(U const& item)
    {
        if (eos_ == end_) 
            VERIFY_(reserve(AllocPolicy::New_Capacity(capacity() + 1)));
        new(end_) T(item);
        return end_++;
    }
//.............................................................................
    bool reserve(size_t n) NO_THROW_()
    {
        size_t old_cap = capacity();
        if (old_cap >= n)
            return true;
        T* p = AllocPolicy::Realloc(beg_, n);
        if (!p)
            return false;
        size_t old_size = size();
        beg_ = p;
        end_ = beg_ + old_size;
        eos_ = beg_ + n;
        return true;
    }
//.............................................................................
    bool is_Equal(fast_vector_impl const& right) const NO_THROW_()
    {
        size_t c = size();
        if(c != right.size())
            return false;
        for (size_t i = 0; i < c; ++i)
        {
            if ((*this)[i] != right[i])
                return false;
        }
        return true;
    }
//.............................................................................
};
//__________________________________________________________________________________
//__________________________________________________________________________________
template<class T, class AllocPolicy = mem_util::malloc_policy<> >
class fast_vector:
    protected fast_vector_impl<T, AllocPolicy>
{
    typedef fast_vector_impl<T, AllocPolicy> Base_;
protected:
    using Base_::beg_;
    using Base_::end_;
    using Base_::eos_;
public:
    typedef T value_type;
    typedef T& reference;
    typedef T const& const_reference;
    typedef size_t size_type;
    typedef T* pointer;
    typedef T const* const_pointer;
    typedef T* iterator;
    typedef T const* const_iterator;
    typedef AllocPolicy TAllocPolicy;
//.............................................................................
    using Base_::operator[];
    using Base_::get;
    using Base_::size;
    using Base_::capacity;
    using Base_::empty;
    using Base_::is_Empty;
    using Base_::back;
    using Base_::front;
    using Base_::begin;
    using Base_::end;
    using Base_::bad_Index;
    using Base_::is_Equal;
    using Base_::reserve;
    using Base_::push_back;
//.............................................................................
    explicit fast_vector() NO_THROW_()
    {}
//.............................................................................
    fast_vector(fast_vector const& right)
    {
        size_t rsize = right.size();
        VERIFY_(reserve(rsize));
        mem_util::Copy(this->beg_, this->end_, right.beg_, right.end_);
        this->end_ = this->beg_ + rsize;
    }
//.............................................................................
    ~fast_vector() NO_THROW_()
    {
        mem_util::Initialized_Destruct(beg_, end_);
    }
//.............................................................................
    fast_vector& operator=(fast_vector const& right)
    {
        if (this != &right)
        {
            size_t rsize = right.size();
            if (rsize > capacity())
            {
                VERIFY_(reserve(rsize));
            }
            else if (size() > rsize)
            {
                resize(rsize);
            }
            mem_util::Copy(beg_, end_, right.beg_, right.end_);
            end_ = beg_ + rsize;
        }
        return *this;
    }
//.............................................................................
    void swap(fast_vector<T, AllocPolicy>& right) NO_THROW_()
    {//:sic: type cast is inaccessible
        Base_::swap(right);
    }
//.............................................................................
    friend bool operator==(fast_vector<T, AllocPolicy> const& left, fast_vector<T, AllocPolicy> const& right) NO_THROW_()
    {
        return left.is_Equal(right);
    }
//.............................................................................
    friend bool operator!=(fast_vector<T, AllocPolicy> const& left, fast_vector<T, AllocPolicy> const& right) NO_THROW_()
    { 
        return !left.is_Equal(right); 
    }
//.............................................................................
    void clear() NO_THROW_()
    {
        mem_util::Initialized_Destruct(beg_, end_);
        Base_::clear();
    }
//.............................................................................
    void pop_back() NO_THROW_()
    {
        ASSERT_(!is_Empty());
        (--end_)->~T();
    }
//.............................................................................
    void resize(size_t new_size)
    {
        size_t old_size = size();
        if (old_size == new_size)
            return;
        if (new_size > old_size)
        {
            VERIFY_(reserve(new_size));
            mem_util::Uninitialized_Construct(end_, beg_ + new_size);
        }
        else
        {
            mem_util::Initialized_Destruct(beg_ + new_size, end_);
        }
        end_ = beg_ + new_size;
    }
//.............................................................................
    template<typename U>
    void resize(size_t new_size, U const& filler)
    {
        size_t old_size = size();
        if (old_size == new_size)
            return;
        if (new_size > old_size)
        {
            reserve(new_size);
            mem_util::Uninitialized_Fill(end_, beg_ + new_size, filler);
        }
        else
        {
            mem_util::Initialized_Destruct(beg_ + new_size, end_);
        }
        end_ = beg_ + new_size;
    }
//.............................................................................
    void erase(T* begin, T* end) NO_THROW_()
    {
        ASSERT_(begin >= beg_);
        ASSERT_(end >= begin);
        ASSERT_(end <= end_);
        mem_util::Erase(begin, end, end_);
        end_ -= end - begin;
    }
//.............................................................................
    void erase(size_t i, size_t count = 1) NO_THROW_()
    {
        ASSERT_(i + count <= size());
        mem_util::Erase(beg_ + i, beg_ + i + count, end_);
        end_ -= count;
    }
//.............................................................................
    T& insert(size_t pos)
    {
        ASSERT_(pos <= size());
        if (eos_ == end_) 
            VERIFY_(reserve(AllocPolicy::New_Capacity(capacity() + 1)));
        mem_util::Insert(beg_ + pos, end_);
        ++end_;
        return *(beg_ + pos);
    }
};

//EOF!
